home *** CD-ROM | disk | FTP | other *** search
/ Cream of the Crop 12 / Cream of the Crop 12 (Part II) / Cream of the Crop 12 (Part II).iso / OS2 / DIKUMUD.ZIP / BOARD.C < prev    next >
Encoding:
C/C++ Source or Header  |  1993-05-30  |  15.2 KB  |  555 lines

  1. /*
  2.   SillyMUD Distribution V1.1b             (c) 1993 SillyMUD Developement
  3.  
  4.   See license.doc for distribution terms.   SillyMUD is based on DIKUMUD
  5. */
  6.  
  7. #include <string.h>
  8. #include <stdio.h>
  9. #include <ctype.h>
  10.  
  11. #include "protos.h"
  12.  
  13.  
  14. #define MAX_MSGS 99                /* Max number of messages.          */
  15. #define MAX_MESSAGE_LENGTH 2048     /* that should be enough            */
  16. #define NUM_BOARDS 3
  17.  
  18. struct message {
  19.   char *date;
  20.   char *title;
  21.   char *author;
  22.   char *text;
  23. };
  24.  
  25. struct board {
  26.   struct message msg[MAX_MSGS+1];
  27.   int number;
  28. };
  29.  
  30. static struct board_lock_struct {
  31.   struct char_data *locked_for;
  32.   bool lock;
  33. } board_lock[NUM_BOARDS];
  34.  
  35.  
  36. int min_read_level[] = { 0, 51, 1};
  37. int min_write_level[] = { 1, 51, 1};
  38. int min_remove_level[] = { 51, 51, 51};
  39.  
  40. struct board boards[NUM_BOARDS];
  41. struct board *curr_board;
  42. struct message *curr_msg;  
  43. extern struct char_data *character_list;
  44.  
  45. /* This sets the minimum level needed to read/write/look at these boards
  46.    mainly included to enable the creation of a "wizard-only" board        */
  47.  
  48. char save_file[NUM_BOARDS][20] = { 
  49.   "mortal.board" , "wiz.board", "skexie.board" };
  50.  
  51.     
  52. /* These are the binary files in which to save/load messages */
  53.  
  54. void board_write_msg(struct char_data *ch, char *arg, int bnum);
  55. int board_display_msg(struct char_data *ch, char *arg, int bnum);
  56. int board_remove_msg(struct char_data *ch, char *arg, int bnum);
  57. void board_save_board();
  58. void board_load_board();
  59. int board_show_board(struct char_data *ch, char *arg, int bnum);
  60. int fwrite_string(char *buf, FILE *fl);
  61.  
  62. /* board.c version 1.2 - Jun 1991 by Twilight.
  63.  
  64. 1.2 changes:
  65.  
  66. c   Added a board and message structure
  67.    took out all pointers in an effort to insure integrity in memory.
  68.    Added differentiation between minimum read levels and minimum write/remove
  69.    levels.
  70.  
  71. 1.1 changes:
  72.  
  73.    Major repairs-- now allows multiple boards define at compile-time.  Set the
  74.    constants NUM_BOARDS and add the new V-Numbers to the if/then structure directly
  75.    below.  Also you must attach the board.c procedure in spec_assign.c as usual.
  76.  
  77.    Log message removals and restrict them to level 15 and above.
  78.    Fixed act message resulting from message removal 
  79.    Removed unused procedure "fix_long_desc"
  80.    Added a message to inform others in room of a read in progress
  81.    Added minimum level check for each board 
  82.    (defined in array min_board_level[NUM_BOARDS]
  83.  
  84. */
  85.  
  86. int board(struct char_data *ch, int cmd, char *arg, struct obj_data *obj, int type)
  87. {
  88.   static int has_loaded = 0;
  89.   char buf[80];
  90.   int bnum = -1;
  91.   int obj_num;
  92.  
  93.   if (type != PULSE_COMMAND)
  94.     return(FALSE);
  95.  
  96.   if (!ch->desc)
  97.     return(0); /* By MS or all NPC's will be trapped at the board */
  98.   
  99.   if (!has_loaded)
  100.     {
  101.       board_load_board();
  102.       has_loaded = 1;
  103.     }
  104.  
  105.   if (!cmd)
  106.     return(FALSE);
  107.  
  108.   /* Identify which board we're dealing with */
  109.   
  110.   obj_num = (obj->item_number);
  111.   if (obj_num == (real_object(3099)))  bnum = 0;
  112.   else if (obj_num == (real_object(3098)))  bnum = 1;
  113.   else if (obj_num == (real_object(3097))) bnum = 2;
  114.  
  115.   switch (cmd) {
  116.   case 15:  /* look */
  117.     return(board_show_board(ch, arg, bnum));
  118.   case 149: /* write */
  119.     board_write_msg(ch, arg, bnum);
  120.     return 1;
  121.   case 63: /* read */
  122.     return(board_display_msg(ch, arg, bnum));
  123.   case 66: /* remove */
  124.     return(board_remove_msg(ch, arg, bnum));
  125.   default:
  126.     return 0;
  127.   }
  128. }
  129.  
  130.  
  131. void board_write_msg(struct char_data *ch, char *arg, int bnum) {
  132.  
  133.   int highmessage;
  134.   char buf[MAX_STRING_LENGTH];
  135.   long ct; /* clock time */
  136.   char *tmstr;
  137.  
  138.   extern struct time_info_data time_info;
  139.   extern char *month_name[];
  140.  
  141.   if ( bnum == -1 ) {
  142.     log("Board special procedure called for non-board object.\r\n");
  143.     send_to_char("This board is not in operation at this time.\n\r", ch);
  144.     return;
  145.   }
  146.  
  147.   curr_board = &boards[bnum];
  148.  
  149.   if (GetMaxLevel(ch) < min_write_level[bnum]) {
  150.     send_to_char("You pick up a quill to write, but realize you're not powerful enough\n\r",ch);
  151.     send_to_char("to submit intelligent material to THIS board.\n\r",ch);
  152.     return;
  153.   }
  154.  
  155.   if ( (curr_board->number) > (MAX_MSGS - 1) ) {
  156.     send_to_char("The board is full already.\n\r", ch);
  157.     return;
  158.   }
  159.  
  160.   /* Check for locks, return if lock is found on this board */
  161.  
  162.   if (board_check_locks(bnum, ch))
  163.     return;
  164.  
  165.   /* skip blanks */
  166.  
  167.   for(; isspace(*arg); arg++);
  168.  
  169.   if (!*arg) {
  170.     send_to_char("The board has now been saved permanently to disk.\n\rTo write a new message, use WRITE followed by a title.\n\r", ch);
  171.     return;
  172.   }
  173.  
  174.   /* Now we're committed to writing a message.  Let's lock the board. */
  175.  
  176.   board_lock[bnum].lock = 1;
  177.   board_lock[bnum].locked_for = ch;
  178.  
  179.   /* Lock set */
  180.  
  181.   highmessage = boards[bnum].number;
  182.   curr_msg = &curr_board->msg[++highmessage];
  183.  
  184.   if (!(strcmp("Topic",arg))) {
  185.     curr_msg = &curr_board->msg[0];
  186.     free(curr_msg->title);
  187.     free(curr_msg->text);
  188.     free(curr_msg->author);
  189.     free(curr_msg->date);
  190.     (boards[bnum].number)--;
  191.   }
  192.   curr_msg->title = (char *)malloc(strlen(arg)+1);
  193.   strcpy(curr_msg->title, arg);
  194.   curr_msg->author = (char *)malloc(strlen(GET_NAME(ch))+1);
  195.   strcpy(curr_msg->author, GET_NAME(ch));
  196.   ct = time(0);
  197.   tmstr = (char *)asctime(localtime(&ct));
  198.   *(tmstr + strlen(tmstr) - 1) = '\0';
  199.   sprintf(buf,"%.10s",tmstr);
  200.   curr_msg->date = (char *)malloc(strlen(buf)+1);
  201.   strcpy(curr_msg->date, buf);
  202.   send_to_char("Write your message. Terminate with a @.\n\r\n\r", ch);
  203.   act("$n starts to write a message.", TRUE, ch, 0, 0, TO_ROOM);
  204.  
  205.   /* Take care of free-ing and zeroing if the message text is already
  206.      allocated previously */
  207.  
  208.   if (curr_msg->text)
  209.     free (curr_msg->text);
  210.   curr_msg->text = 0;
  211.  
  212.   /* Initiate the string_add procedures from comm.c */
  213.  
  214.   ch->desc->str = &curr_msg->text;
  215.   ch->desc->max_str = MAX_MESSAGE_LENGTH;
  216.   (boards[bnum].number)++;
  217.   if (boards[bnum].number < 0)
  218.     boards[bnum].number = 0;
  219. }
  220.  
  221. int board_remove_msg(struct char_data *ch, char *arg, int bnum) {
  222.  
  223.   /* This should now be fixed so that low level chars can remove armor and such. */
  224.  
  225.   int ind, tmessage;
  226.   char buf[256], number[MAX_INPUT_LENGTH];
  227.   
  228.   one_argument(arg, number);
  229.   
  230.   if (!*number || !isdigit(*number))
  231.     return(0);
  232.   
  233.   if (!(tmessage = atoi(number))) return(0);
  234.   
  235.   if ( bnum == -1 ) {
  236.     log("Board special procedure called for non-board object.\r\n");
  237.     send_to_char("This board is not in operation at this time.\n\r", ch);
  238.     return 1;
  239.   }
  240.  
  241.   curr_board = &boards[bnum];
  242.  
  243.   if (GetMaxLevel(ch) < min_remove_level[bnum]) {
  244.     send_to_char("You try and grab one of the notes of the board but get a nasty\n\r",ch);
  245.     send_to_char("shock.  Maybe you'd better leave it alone.\n\r",ch);
  246.     return 1;
  247.   }
  248.  
  249.   if (curr_board->number < 1) {
  250.     send_to_char("The board is empty!\n\r", ch);
  251.     return(1);
  252.   }
  253.  
  254.   if (tmessage < 0 || tmessage > curr_board->number) {
  255.     send_to_char("That message exists only in your imagination..\n\r",
  256.          ch);
  257.     return(1);
  258.   }
  259.  
  260.   /* Check for board locks, return if lock is found */
  261.   
  262.   if (board_check_locks(bnum, ch))
  263.     return(1);
  264.  
  265.   ind = tmessage;
  266.  
  267.   free(curr_board->msg[ind].text);
  268.   free(curr_board->msg[ind].date);
  269.   free(curr_board->msg[ind].author);
  270.   free(curr_board->msg[ind].title);
  271.  
  272.   for ( ; ind < (curr_board->number) ; ind++ )
  273.     curr_board->msg[ind] = curr_board->msg[ind+1];
  274.  
  275. /* You MUST do this, or the next message written after a remove will */
  276. /* end up doing a free(curr_board->msg[ind].text) because it's not!! */
  277. /* Causing strange shit to happen, because now the message has a     */
  278. /* To a memory location that doesn't exist, and if THAT message gets */
  279. /* Removed, it will destroy what it's pointing to. THIS is the board */
  280. /* Bug we've been looking for!        -=>White Gold<=-               */
  281.  
  282.   curr_board->msg[curr_board->number].text = NULL;
  283.   curr_board->msg[curr_board->number].date = NULL;
  284.   curr_board->msg[curr_board->number].author = NULL;
  285.   curr_board->msg[curr_board->number].title = NULL;
  286.  
  287.   curr_board->number--;
  288.  
  289.   send_to_char("Message removed.\n\r", ch);
  290.   sprintf(buf, "%s just removed message %d.", ch->player.name, tmessage);
  291.  
  292.   /* Removal message also repaired */
  293.  
  294.   act(buf, FALSE, ch, 0, 0, TO_ROOM);
  295.   sprintf((buf+strlen(buf)-1)," from board %d.",bnum);
  296.   log(buf);  /* Message removals now logged. */
  297.  
  298.   board_save_board(bnum);
  299.   return(1);
  300. }
  301.  
  302. char *fix_returns(char *text_string)
  303. {
  304.   char *localbuf;
  305.   int point=0;
  306.   int point2 = 0;
  307.  
  308.   if (!text_string) {
  309.     CREATE(localbuf,char,2);
  310.     strcpy(localbuf,"\n");
  311.     return(localbuf);
  312.   }
  313.  
  314.   if (!(*text_string)) {
  315.     CREATE(localbuf,char,strlen("(NULL)")+1);
  316.     strcpy(localbuf,"(NULL)");
  317.     return(localbuf);
  318.   }
  319.  
  320.   CREATE(localbuf,char,strlen(text_string));
  321.  
  322.   while(*(text_string+point) != '\0') 
  323.     if (*(text_string+point) != '\r') {
  324.       *(localbuf+point2) = *(text_string+point);
  325.       point2++;
  326.       point++;
  327.     }
  328.     else
  329.       point++;
  330.   *(localbuf + point2) = '\0'; /* You never made sure of null termination */
  331.   return(localbuf);
  332. }
  333.   
  334. void board_save_board(bnum) {
  335.  
  336.   FILE *the_file;
  337.   int ind;
  338.   char buf[256];
  339.   char *temp_add;
  340.  
  341.   /* We're assuming the board number is valid since it was passed by
  342.      out own code */
  343.  
  344.   curr_board = &boards[bnum];
  345.  
  346.   the_file = fopen(save_file[bnum], "w");
  347.  
  348.   if (!the_file) {
  349.       log("Unable to open/create savefile for bulletin board..\n\r");
  350.       return;
  351.     }
  352.  
  353.   fprintf(the_file," %d ", curr_board->number);
  354.   for (ind = 0; ind <= curr_board->number; ind++) {
  355.     curr_msg = &curr_board->msg[ind];
  356.     fwrite_string(curr_msg->title, the_file);
  357.     fwrite_string(curr_msg->author, the_file);
  358.     fwrite_string(curr_msg->date, the_file);
  359.     fwrite_string((temp_add = fix_returns(curr_msg->text)), the_file);
  360.     free(temp_add);
  361.   }
  362.   fclose(the_file);
  363.   return;
  364. }
  365.  
  366. void board_load_board() {
  367.  
  368.   FILE *the_file;
  369.   int ind;
  370.   int bnum;
  371.   char buf[256];
  372.   
  373.   memset(boards, 0, sizeof(boards)); /* Zero out the array, make sure no */
  374.                                      /* Funky pointers are left in the   */
  375.                                      /* Allocated space                  */
  376.  
  377.   for ( bnum = 0 ; bnum < NUM_BOARDS ; bnum++ ) {
  378.     board_lock[bnum].lock = 0;
  379.     board_lock[bnum].locked_for = 0;
  380.   }
  381.  
  382.   for (bnum = 0; bnum < NUM_BOARDS; bnum++) {
  383.     boards[bnum].number = -1;
  384.     the_file = fopen(save_file[bnum], "r");
  385.     if (!the_file) {
  386.       sprintf(buf,"Can't open message file for board %d.\n\r",bnum);
  387.       log(buf,0);
  388.       continue;
  389.     }
  390.  
  391.     fscanf( the_file, " %d ", &boards[bnum].number);
  392.     if (boards[bnum].number < 0 || boards[bnum].number > MAX_MSGS || 
  393.     feof(the_file)) {
  394.       log("Board-message file corrupt, nonexistent, or empty.\n\r");
  395.       boards[bnum].number = -1;
  396.       fclose(the_file);
  397.       continue;
  398.     }
  399.  
  400.     curr_board = &boards[bnum];
  401.  
  402.     for (ind = 0; ind <= curr_board->number; ind++) {
  403.       curr_msg = &curr_board->msg[ind];
  404.       curr_msg->title = (char *)fread_string (the_file);
  405.       curr_msg->author = (char *)fread_string (the_file);
  406.       curr_msg->date = (char *)fread_string (the_file);
  407.       curr_msg->text = (char *)fread_string (the_file);
  408.     }
  409.     fclose(the_file);
  410.   }
  411. }
  412.  
  413. int board_display_msg(struct char_data *ch, char *arg, int bnum)
  414. {
  415.   char buf[512], number[MAX_INPUT_LENGTH], buffer[MAX_STRING_LENGTH];
  416.   int tmessage;
  417.  
  418.   one_argument(arg, number);
  419.  
  420.   if (!*number || !isdigit(*number))
  421.     return(0);
  422.  
  423.   if (!(tmessage = atoi(number))) return(0);
  424.  
  425.   curr_board = &boards[bnum];
  426.  
  427.   if ((boards[bnum].number != -1) &&
  428.       (tmessage >= 0 && tmessage <= curr_board->number) &&
  429.       (GetMaxLevel(ch) < min_read_level[bnum]) &&
  430.       (strcmp(GET_NAME(ch), curr_board->msg[tmessage].author))) ;
  431.   else 
  432.   if ( GetMaxLevel(ch) < min_read_level[bnum] ) {
  433.     send_to_char("You try and look at the messages on the board but you\n\r",
  434.                  ch);
  435.     send_to_char("cannot comprehend their meaning.\n\r\n\r",ch);
  436.     act("$n tried to read the board, but looks bewildered.",TRUE,ch, 0, 0,
  437.         TO_ROOM);
  438.     return(1);
  439.   }
  440.  
  441.   if (boards[bnum].number == -1) {
  442.     send_to_char("The board is empty!\n\r", ch);
  443.     return(1);
  444.   }
  445.   
  446.   if (tmessage < 0 || tmessage > curr_board->number) {
  447.     send_to_char("That message exists only in your imagination..\n\r",ch);
  448.     return(1);
  449.   }
  450.  
  451.   curr_msg = &curr_board->msg[tmessage];
  452.  
  453.   sprintf(buf, "$n reads message %d titled : %s.",tmessage, curr_msg->title);
  454.   act(buf, TRUE, ch, 0, 0, TO_ROOM);
  455.   sprintf(buffer, "Message %2d (%s): %-15s -- %s", tmessage, curr_msg->date, curr_msg->author, curr_msg->title );
  456.   sprintf(buffer + strlen(buffer), "\n\r----------\n\r%s", (curr_msg->text?curr_msg->text:"(null)"));
  457.   page_string(ch->desc, buffer, 1);
  458.   return(1);
  459. }
  460.         
  461. int board_show_board(struct char_data *ch, char *arg, int bnum)
  462. {
  463.   int i;
  464.   char buf[MAX_STRING_LENGTH], tmp[MAX_INPUT_LENGTH];
  465.  
  466.   one_argument(arg, tmp);
  467.  
  468.   if (!*tmp || !isname(tmp, "board bulletin"))
  469.     return(0);
  470.  
  471.   if ((GetMaxLevel(ch) < min_read_level[bnum]) && (bnum !=5)) 
  472.     /* Skip if board 5 (Reimb board) */
  473.     send_to_char("You try and look at the messages on the board but you\n\r",ch);
  474.     send_to_char("cannot comprehend their meaning.\n\r",ch);
  475.     act("$n tried to read the board, but looks bewildered.",TRUE,ch, 0, 0, TO_ROOM);
  476.     return(1);
  477.   }
  478.  
  479.   curr_board = &boards[bnum];
  480.  
  481.   act("$n studies the board.", TRUE, ch, 0, 0, TO_ROOM);
  482.  
  483.   strcpy(buf,"This is a bulletin board. Usage: READ/REMOVE <messg #>, WRITE <header>\n\r");
  484.   if (boards[bnum].number == -1)
  485.     strcat(buf, "The board is empty.\n\r");
  486.   else {
  487.     sprintf(buf + strlen(buf), "There are %d messages on the board.\n\r",
  488.         curr_board->number);
  489.     sprintf(buf + strlen(buf), "\n\rBoard Topic:\n\r%s------------\n\r",curr_board->msg[0].text);
  490.     for ( i = 1 ; i <= curr_board->number ; i++ ) 
  491. /*      if (((GET_MAX_LEVEL(ch) < min_read_level[bnum]) &&
  492.            (strcmp(ch->name, curr_board->msg[i].author))) ||
  493.           (GET_MAX_LEVEL(ch) >= min_read_level[bnum]))  */
  494.        sprintf(buf + strlen(buf), "%-2d : %-15s (%s) -- %s\n\r", i , 
  495.                curr_board->msg[i].author, curr_board->msg[i].date,
  496.                curr_board->msg[i].title);
  497.   }
  498.   page_string(ch->desc, buf, 1);
  499.   return(1);
  500. }
  501.  
  502. int fwrite_string (char *buf, FILE *fl)
  503. {
  504.   return (fprintf(fl, "%s~\n", buf));
  505. }
  506.  
  507. int board_check_locks (int bnum, struct char_data *ch) {
  508.   
  509.   char buf[MAX_INPUT_LENGTH];
  510.   struct char_data *tmp_char;
  511.   bool found = FALSE;
  512.   if (!board_lock[bnum].lock) return(0);
  513.   
  514.   /* FIRST lets' see if this character is even in the game anymore! -WG-*/
  515.   for (tmp_char = character_list; tmp_char; tmp_char = tmp_char->next)
  516.     {
  517.       if (tmp_char == board_lock[bnum].locked_for)
  518.         {
  519.           found = TRUE;
  520.           break;
  521.         }
  522.     }
  523.   if (!found)
  524.     {
  525.       log("Board: board locked for a user not in game.");
  526.       board_lock[bnum].lock = 0;
  527.       board_lock[bnum].locked_for = NULL;
  528.       return(0);
  529.     }
  530.  
  531.   /* Check for link-death of lock holder */
  532.  
  533.   if (!board_lock[bnum].locked_for->desc) {
  534.     sprintf(buf,"You push %s aside and approach the board.\n\r",board_lock[bnum].locked_for->player.name);
  535.     send_to_char(buf, ch);
  536.   }
  537.  
  538.   /* Else see if lock holder is still in write-string mode */
  539.  
  540.   else if (board_lock[bnum].locked_for->desc->str) { /* Lock still holding */
  541.     sprintf(buf,"You try to approach the board but %s blocks your way.\n\r",board_lock[bnum].locked_for->player.name);
  542.     send_to_char(buf, ch);
  543.     return (1);
  544.   }
  545.  
  546.   /* Otherwise, the lock has been lifted */
  547.  
  548.   board_save_board(bnum);
  549.   board_lock[bnum].lock = 0;
  550.   board_lock[bnum].locked_for = 0;
  551.   return(0);
  552. }
  553.   
  554.